from FireFoxDriverTool.FireFoxDriver import FireFoxDriver, ByType
from pyquery import PyQuery as pq
import time
import userConfig
import hashlib
import re
from MailTool.Mail import Mail
import json
from Match.Match import Match
from MongoBetTool.MongoBet import MongoBet
from Balance.Balance import Balance
from LoggingTool.Logging import Logging

class Bet365(object):
    def __init__(self):
        self.browser = FireFoxDriver(userConfig.URL)
        self.collections = dict()
        self.runnings = dict()
        self.section = 0
        self.row = 0
        self.mongo = MongoBet()
        self.all = 0
        self.first = True
        self.league = None
        self.balance = Balance()

    # 强制登录
    def login(self):
        try:
            while ((self.browser.isElementPresent(ByType.CLASS_NAME, 'hm-Balance ') == False)):
                self.browser.clickElement(ByType.ID, 'dv1')
                while (self.browser.isElementPresent(ByType.XPATH,"//div[@class='hm-Login_UserNameWrapper ']/input") == False):
                    pass

                time.sleep(2)
                self.browser.click4Element(ByType.XPATH, "//div[@class='hm-Login_UserNameWrapper ']/input")
                self.browser.setElementText(ByType.XPATH, "//div[@class='hm-Login_UserNameWrapper ']/input","chenggang1986")
                time.sleep(2)
                self.browser.click4Element(ByType.XPATH, "//div[@class='hm-Login_PasswordWrapper ']/input[1]")
                self.browser.setElementText(ByType.XPATH, "//div[@class='hm-Login_PasswordWrapper ']/input[2]", "xuzhou139")
                self.browser.click4Element(ByType.CSS_SELECTOR, '.hm-Login_LoginBtn ')
                while ((self.browser.isElementPresent(ByType.CLASS_NAME, 'hm-Balance ') == False)):
                    pass

                elements = self.browser.elements(ByType.CSS_SELECTOR, '.hm-BigButton ')
                for element in elements:
                    if self.browser.text2forElement(element) == userConfig.BetSport:
                        self.browser.click3Element(element)

        except Exception as e:
            print(str(e))
            self.login()


    #判断是否是足球项目
    def hasFootball(self):
        self.browser.closePages()
        # time.sleep(1)
        xPathName = "//div[contains(@class,'ipo-ClassificationBar_ButtonContainer')]/div[2]/div[2]"
        return self.browser.textForElement(ByType.XPATH, xPathName) == userConfig.BetSportItem

    #当前选中的是否是足球
    def isSelectFootball(self):
        self.browser.closePages()
        # time.sleep(1)
        xPathName = "//div[contains(@class,'ipo-ClassificationBarButtonBase_Selected')]/div[2]"
        return self.browser.textForElement(ByType.XPATH, xPathName) == userConfig.BetSportItem

    #是否是上半场亚洲盘
    def isAsiaHalf(self):
        self.browser.closePages()
        xPathName = "//div[contains(@class,'ipo-InPlayClassificationMarketSelectorDropDown_Button')]"
        return self.browser.textForElement(ByType.XPATH, xPathName) == userConfig.AsiaHalfItem


    #切换到足球比赛
    def switchToFootball(self):
        self.browser.closePages()
        time.sleep(1)
        xPathName = "//div[contains(@class,'ipo-ClassificationBar_ButtonContainer')]/div[2]/div[2]"
        self.browser.clickElement(ByType.XPATH, xPathName)

    #切换到上半场亚洲盘
    def switchToAsiaHalf(self):
        self.browser.closePages()
        time.sleep(1)
        xPathName = "//div[contains(@class,'ipo-InPlayClassificationMarketSelectorDropDown_Button')]"
        self.browser.clickElement(ByType.XPATH, xPathName)
        time.sleep(1)
        xPathName = "//div[contains(@class,'wl-DropDown_Inner ipo-InPlayClassificationMarketSelectorDropDown_Inner')]/div[2]"
        self.browser.clickElement(ByType.XPATH, xPathName)


    #返回网页源码
    def pageSource(self):
        return self.browser.driver.page_source

     #获取当前比赛的时间
    def timeForMatch(self, aMatch):
        timer = aMatch.find('.ipo-InPlayTimer').text()
        return timer.replace(':', '.') if timer else 0

    #获取当前比赛双方的名称
    def nameForMatch(self, aMatch):
        items = aMatch.find('.ipo-TeamStack_TeamWrapper').items()
        names = [item.text() for item in items]
        return ('{} v {}'.format(names[0], names[1]))

    #获取当前比赛的Md5
    def md5ForNameOfMatch(self, aMatch):
        name = self.nameForMatch(aMatch)
        return self.md5ForName(name)

    #获取比赛名的Md5
    def md5ForName(self, name):
        m = hashlib.md5()
        m.update(name.encode('utf8'))
        return m.hexdigest()

    #比赛进球
    def fullHandicapForMatch(self, aMatch):
        goals = aMatch.find('.gl-ParticipantCentered_Handicap').text()
        if goals:
            patt = re.compile(r"(\d+\.\d+)")
            return patt.search(goals).group()
        else:
            return 0

    def fullRatioForMatch(self, aMatch):
        index = 0
        for item in aMatch.find('.ipo-MainMarketRenderer ').items():
            if index == 0:
                ratio = item.find('.gl-ParticipantCentered_Odds').text()
                if ratio:
                    if 'SP' in ratio:
                        return None
                    else:
                        ratios = ratio.split(' ')
                        return sorted([float(ratios[0]), float(ratios[1])])
        return None

    #上半场初盘
    def halfHandicapForMatch(self, aMatch):
        index = 0
        for item in aMatch.find('.ipo-MainMarketRenderer ').items():
            if index == 2:
                handicap = item.find('.gl-ParticipantCentered_Handicap').text()
                if handicap:
                    patt = re.compile(r"高于(.*)低于")
                    return patt.search(handicap).group(1).strip()
            index += 1
        return None

    #获取上半场赔率
    def halfOddsForMatch(self, aMatch):
        index = 0
        for item in aMatch.find('.ipo-MainMarketRenderer ').items():
            if index == 2:
                odds = item.find('.gl-ParticipantCentered_Odds').text()
                if odds:
                    patt = re.compile(r"(\d+\.\d+)")
                    return patt.search(odds).group()
            index += 1
        return 0

    #获取赔率
    def fullOddsForMatch(self, aMatch):
        for item in aMatch.find('.ipo-MainMarketRenderer').items():
            if item.find('.gl-ParticipantCentered_Handicap'):
                odds = item.find('.gl-ParticipantCentered_Odds').text()
                if odds:
                    return odds.split(' ')[0]
        return  0

    #当前比分
    def scoreForMatch(self, aMatch):
        score = aMatch.find('.ipo-TeamPoints_TeamScore').text()
        return score.replace(' ', ':') if score else None

    #禁止的联赛
    def hasForbiddenLeague(self, aLeague):
        for forbidden in userConfig.ForbiddenLeagues:
            if forbidden in aLeague:
                return True
        return False

    #禁止的比赛
    def hasForbiddenMatch(self, names):
        for forbidden in userConfig.ForbiddenMatches:
            if forbidden in names:
                return True
        return False

    #点击投注
    def clickBetForMatch(self):
        selector = 'div.ipo-Competition:nth-child(%d) > div:nth-child(3) > ' \
                   'div:nth-child(%d) > div:nth-child(1) > div:nth-child(2) >' \
                   ' div:nth-child(3) > div:nth-child(1)' %(self.section, self.row)
        element = self.browser.element(ByType.CSS_SELECTOR, selector)
        text = self.browser.text2forElement(element)
        if element != None and len(text) != 0:
            self.browser.click2Element(element)
            try:
                frame = self.browser.element(ByType.CLASS_NAME, 'bw-BetslipWebModule_Frame')
                self.browser.switch2frame(frame)
                while (self.browser.isElementPresent(ByType.CSS_SELECTOR, '.bs-Header_RemoveAllLink') == False):
                    # print('clickBetForMatch is running')
                    pass
            except Exception as e:
                print('clickBetForMatch has exception-----', e)
            finally:
                self.browser.switch2default()


    #关闭投注窗口
    def closeBetForMatch(self):
        try:
            frame = self.browser.element(ByType.CLASS_NAME, 'bw-BetslipWebModule_Frame')
            self.browser.switch2frame(frame)
            remove = self.browser.element2(ByType.CSS_SELECTOR, '.bs-Header_RemoveAllLink')
            if remove != None:
                self.browser.click3Element(remove)
                while (self.browser.isElementPresent(ByType.CSS_SELECTOR, '.bs-Header_RemoveAllLink') == True):
                    # print('closeBetForMatch is running')
                    pass
        except Exception as e:
            print('closeBetForMatch has exception-----', e)
        finally:
            self.browser.switch2default()

    #下注
    def doPay(self, names, times, all_goals):
        #刷新金额并获取投注前的金额
        # self.refreshMoney()
        money_before_bet = self.getMoney()
        # 先关闭投注窗口
        self.closeBetForMatch()
        #再打开投注窗口
        self.clickBetForMatch()
        try:
            frame = self.browser.element(ByType.CLASS_NAME, 'bw-BetslipWebModule_Frame')
            self.browser.switch2frame(frame)
            # 判断比赛有没有错乱的情况
            theNames = self.browser.textForElement(ByType.XPATH, "//div[@class='bs-Selection']/div[3]")
            odds = self.browser.textForElement(ByType.CSS_SELECTOR, '.bs-Odds')
            handicap = self.browser.textForElement(ByType.CSS_SELECTOR, '.bs-Selection_Handicap')

            names_ok = (theNames != None and names == theNames)
            odds_ok = (odds != None and float(odds) >= float(times))
            handicap_ok = (handicap != None and ((float(handicap) > all_goals) and (float(handicap) < all_goals + 1)))

            if names_ok and odds_ok and handicap_ok:
                self.browser.setElementText(ByType.XPATH, "//input[@class='stk bs-Stake_TextBox']", str(self.balance.get(times)))
                while ((self.browser.isElementPresent(ByType.CSS_SELECTOR, '.bs-Footer') == True)):
                    print('还没投完注')
                    self.handicapOut(all_goals)
                    self.browser.clickElement(ByType.CSS_SELECTOR, '.bs-Footer')
                    time.sleep(2)
            else:
                errorInfo = {'info':{'theNames':theNames, 'names':names, 'times':times, 'odds':odds, 'all_goals':all_goals, 'handicap':handicap},
                           'result':{'names_ok':names_ok, 'odds_ok':odds_ok, 'handicap_ok':handicap_ok}}
                print('投注信息有误-----', errorInfo)
                Mail.send('误之', json.dumps(errorInfo, ensure_ascii=False))
        except Exception as e:
            print('doPay has exception-----', e)
        finally:
            self.browser.switch2default()

        # 如果金额发生变化，则认为投注成功
        money_after_bet = self.getMoney()
        if money_after_bet != money_before_bet:
            md5 = self.md5ForName(names)
            self.collections[md5]['times_betteds'][times] = True
            self.mongo.saveMatch(userConfig.MONGO_TABLE_BETS, self.collections[md5])
            self.mongo.updateMatch(userConfig.MONGO_TABLE_COLLECTIONS, self.collections[md5])
            hint = '下之，times={}, rmb={}'.format(times, self.balance.get(times))
            Mail.send( hint, json.dumps(self.collections[md5], ensure_ascii=False))

            # 关闭弹出来的设置
            time.sleep(5)
            notNowBtn = self.browser.element(ByType.CSS_SELECTOR, '.eba-AdvertWindow_NotNowBtnText')
            if notNowBtn != None:
                self.browser.click3Element(notNowBtn)

    #投注前的金额
    def getMoney(self):
        money_bet = self.browser.textForElement(ByType.CSS_SELECTOR, '.hm-Balance')
        return money_bet.split(' ')[0] if money_bet != None else None

    # 刷新money
    def refreshMoney(self):
        self.browser.clickElement(ByType.CSS_SELECTOR, '.hm-Balance')
        self.browser.clickElement(ByType.CSS_SELECTOR, '.hm-BalanceDropDown_RefreshBalance')
        time.sleep(5)
        self.browser.clickElement(ByType.CSS_SELECTOR, '.hm-Balance')

    #处理大小盘不符合的投注
    def handicapOut(self, all_goals):
        element = self.browser.element(ByType.CSS_SELECTOR, '.bs-RemoveColumn_Button')
        handicap = self.browser.textForElement(ByType.CSS_SELECTOR, '.bs-Selection_Handicap')
        if handicap != None and element != None:
            if (float(handicap) <= all_goals) or (float(handicap) >= all_goals+1):
                self.browser.click2Element(element)

    #解析所有比赛
    def allMatches(self):
        doc = pq(self.pageSource())
        allLeagues = doc('.ipo-Competition-open').items()
        self.section = 0
        self.all = 0
        for aLeague in allLeagues:
            self.section += 1
            everyLeagueName = aLeague.find('.ipo-CompetitionButton_NameLabelHasMarketHeading').text()
            #如果有禁止的比赛，则直接返回
            forbidden_ok = self.hasForbiddenLeague(everyLeagueName)
            if forbidden_ok:
                continue

            self.league = everyLeagueName
            matches = aLeague.find('.ipo-Fixture_MainMarkets').items()
            self.row = 0
            for aMatch in matches:
                self.row += 1
                self.all += 1
                yield aMatch


    #解析上半场比赛
    def procHalfMatches(self):
        pass

    def procFullMatches(self):
        #是否要更新收入表和加载数据库
        self.balance.updateBalance()
        if self.first:
            self.collections = self.mongo.queryMatches(userConfig.MONGO_TABLE_COLLECTIONS)
            self.first = False

        print('目前进行的比赛数目为：', self.all)
        print('目前收藏的比赛数目为：', len(self.collections))

        self.runnings.clear()
        self.runnings = {key:False for key in self.collections.keys()}

        for aMatch in self.allMatches():
            names = self.nameForMatch(aMatch)
            if self.hasForbiddenMatch(names) == True:
                continue

            md5 = self.md5ForNameOfMatch(aMatch)
            time_now = float(self.timeForMatch(aMatch))
            if md5 in self.collections:
                self.runnings[md5] = True

            #如果进行中的比赛不在收藏中，则不解析其他的比赛信息 或者已经加入的赛前比赛
            if (time_now != 0 and md5 not in self.collections) or (time_now == 0 and md5 in self.collections):
                continue

            score = self.scoreForMatch(aMatch)
            handicap = self.fullHandicapForMatch(aMatch)
            odds = float(self.fullOddsForMatch(aMatch))
            ratio = self.fullRatioForMatch(aMatch)
            all_goals = int(score.split(':')[0]) + int(score.split(':')[1]) if score != None else 0

            # 收藏中添加符合的比赛
            min_initial_time = userConfig.RULE_FULL['min_initial_time']
            max_initial_time = userConfig.RULE_FULL['max_initial_time']
            full_handicaps = userConfig.RULE_FULL['full_handicaps']
            min_full_ratio = userConfig.RULE_FULL['min_full_ratio']
            max_full_ratio = userConfig.RULE_FULL['max_full_ratio']

            time_ok = (time_now >= min_initial_time and time_now <= max_initial_time)
            handicap_ok = (handicap in full_handicaps and odds <= full_handicaps[handicap])
            ratio_ok = (ratio != None and ratio[0] <= min_full_ratio and  ratio[1] >= max_full_ratio)

            # if True:
            if time_ok and handicap_ok and ratio_ok:  #满足时间和赔率要求
                matchDict = {
                    'parties_name' : names,
                    'score' : score,
                    'latest_goal_time' : 0,
                    'goals_time' : [],
                    'times_betteds' : {'3':False, '2': False, '4':False},
                    'full_handicap' : handicap,
                    'handicap_odds':odds,
                    'play_time' : 0.0,
                    'start_time' : None,
                    '_id' : md5,
                    'combined_goals' : 0,
                    'ratio':ratio,
                    'league':self.league
                }

                #如果不在，则收藏
                # if True:
                if md5 not in self.collections :
                    self.collections[md5] = matchDict

            # 如果比赛正在进行且在收藏中
            if md5 in self.collections.keys() and time_now != 0:
                # 更新当前的比赛时间
                self.collections[md5]['play_time'] = time_now

                # 更新比赛开始的时间且加入数据库
                if self.collections[md5]['start_time'] == None:
                    self.collections[md5]['start_time'] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                    self.mongo.saveMatch(userConfig.MONGO_TABLE_COLLECTIONS, self.collections[md5])
                    Mail.send('入之', json.dumps(self.collections[md5], ensure_ascii=False))


                if self.collections[md5]['score'] != score:  # 有进球的情况
                    # 针对几分钟内狂进球的异常情况 根据两球相隔时间判断
                    last_goal_time = self.collections[md5]['latest_goal_time']
                    if (last_goal_time == 0) or ((time_now - last_goal_time) >= userConfig.RULE_FULL['goal_time_interval']):
                        self.collections[md5]['combined_goals'] += 1
                    else:
                        print('5分钟之内连续进球了啊')

                    self.collections[md5]['goals_time'].append(time_now)
                    self.collections[md5]['score'] = score
                    self.collections[md5]['latest_goal_time'] = time_now
                    self.mongo.updateMatch(userConfig.MONGO_TABLE_COLLECTIONS, self.collections[md5])

                    betted_success = False
                    win_hint = '中之 '
                    for (times, betted) in self.collections[md5]['times_betteds'].items():#判断进球是否下注，且列出下注的倍数
                        if betted == True:
                            self.balance.win(times)
                            betted_success = True
                            win_hint = win_hint + times + 'times '
                    if betted_success: # 进球且已经下注，则增加记录
                        self.mongo.saveMatch(userConfig.MONGO_TABLE_SUCCESSES, self.collections[md5])
                        self.mongo.deleteMatch(userConfig.MONGO_TABLE_COLLECTIONS, self.collections[md5])
                        Mail.send(win_hint, json.dumps(self.collections[md5], ensure_ascii=False))
                        self.collections.pop(md5)
                        continue

                min_latest_goal_time = userConfig.RULE_FULL['min_latest_goal_time']
                max_latest_goal_time = userConfig.RULE_FULL['max_latest_goal_time']
                min_bet_time = userConfig.RULE_FULL['min_bet_time']
                max_first_goal_time = userConfig.RULE_FULL['max_first_goal_time']
                min_already_full_goals = userConfig.RULE_FULL['min_already_full_goals']
                max_already_full_goals = userConfig.RULE_FULL['max_already_full_goals']

                latest_goal_time = self.collections[md5]['latest_goal_time']
                # combined_goals = self.collections[md5]['combined_goals']
                goals_time = self.collections[md5]['goals_time']
                first_goal_time = float(goals_time[0]) if len(goals_time) != 0 else userConfig.RULE_FULL['full_time']

                latest_goal_time_ok = (latest_goal_time >= min_latest_goal_time and latest_goal_time <= max_latest_goal_time)
                first_goal_time_ok = (first_goal_time <= max_first_goal_time)
                goals_ok = (all_goals == min_already_full_goals or all_goals == max_already_full_goals)
                min_bet_time_ok = (time_now >= min_bet_time)
                target_achieved_ok = False

                times_betted = None
                for (key, val) in self.collections[md5]['times_betteds'].items():
                    if odds >= float(key) and val == False:
                        times_betted = key
                        break

                if times_betted != None:
                    target_achieved_ok = (self.balance.isTargetAchieved(times_betted) == False)

                if latest_goal_time_ok and goals_ok and first_goal_time_ok and target_achieved_ok and min_bet_time_ok:
                    self.doPay(names, times_betted, all_goals)
                else:
                    print('names={}, latest_goal_time_ok={}, goals_ok={}, times_betted={}, first_goal_time_ok={}, target_achieved_ok={}, min_bet_time_ok={} '.format(
                        names, latest_goal_time_ok, goals_ok, times_betted, first_goal_time_ok, target_achieved_ok, min_bet_time_ok))

        #删除已经比赛完的
        for (key, running) in self.runnings.items():
            if running == False and key in self.collections:
                already_betted = False
                lost_hint = '输之 '
                for (times, betted) in self.collections[key]['times_betteds'].items():
                    if betted == True:
                        self.balance.lose(times)
                        already_betted = True
                        lost_hint = lost_hint + times + 'times '

                if already_betted == True:
                    Mail.send(lost_hint, json.dumps(self.collections[key], ensure_ascii=False))
                else:
                    Mail.send('删之！', json.dumps(self.collections[key], ensure_ascii=False))

                self.mongo.deleteMatch(userConfig.MONGO_TABLE_COLLECTIONS,self.collections[key])
                self.collections.pop(key)

